----------------------------------------------------------------------------------
--    _____
--   /     \
--  /____   \____
-- / \===\   \==/
--/___\===\___\/  AVNET
--     \======/
--      \====/    
--
----------------------------------------------------------------------------------
-- This design is the property of Avnet.  Publication of this
-- design is not authorized without written consent from Avnet.
-- 
-- Any modifications that are made to the Source Code are 
-- done at the user's sole risk and will be unsupported.
--
-- Disclaimer:
--    Avnet, Inc. makes no warranty for the use of this code or design.
--    This code is provided  "As Is". Avnet, Inc assumes no responsibility for
--    any errors, which may appear in this code, nor does it make a commitment
--    to update the information contained herein. Avnet, Inc specifically
--    disclaims any implied warranties of fitness for a particular purpose.
--                     Copyright(c) 2010 Avnet, Inc.
--                             All rights reserved.
--
--
-- This copyright and support notice must be retained as part 
-- of this text at all times. 
--
-- Xilinx products are not intended for use in life support
-- appliances, devices, or systems. Use in such applications is
-- expressly prohibited.
--
----------------------------------------------------------------------------------
--
----------------------------------------------------------------------------------
-- FILE NAME : ml605_fmc150.vhd
--
-- AUTHOR    : Peter Kortekaas
--
-- COMPANY   : 4DSP
--
-- ITEM      : 1
--
-- UNITS     : Entity       - ml605_fmc150
--             architecture - ml605_fmc150_syn
--
-- LANGUAGE  : VHDL
--
-------------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------------
-- DESCRIPTION
-- ===========
--
-- This file toplevel design file containing:
--  * Physical interface to the ADCs on the FMC150
--  * DDC - Digital Down Converter supporting an input data rate of 61.44Msps and
--    decimation of 8 (output data rate 7.68Msps)
--  * Quadrature sinusoid and Impulse signal generation
--  * DUC - Digital Up Converter supporting an input data rate of 3.84Msps and
--    upconversion of 16 (output data rate 61.44MspsMsps)
--  * Physical interface to the DACs on the FMC150
--  * Control block for configuring the FMC150 through SPI busses
--
-------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------
-- Library declarations
-------------------------------------------------------------------------------------
library ieee;
  use ieee.std_logic_unsigned.all;
  use ieee.std_logic_misc.all;
  use ieee.std_logic_arith.all;
  use ieee.std_logic_1164.all;
--  use IEEE.NUMERIC_STD.ALL;
library unisim;
  use unisim.vcomponents.all;

-------------------------------------------------------------------------------------
-- Entity declaration
-------------------------------------------------------------------------------------
entity ml605_fmc150 is
port (

  --ML605 Resources
  cpu_reset        : in    std_logic; -- CPU RST button, SW10
  sysclk_p        : in    std_logic;
  sysclk_n        : in    std_logic;
  gpio_led         : out   std_logic_vector(7 downto 0);
  gpio_dip_sw      : in    std_logic_vector(7 downto 0);
  gpio_led_c       : out   std_logic;
  gpio_led_e       : out   std_logic;
  gpio_led_n       : out   std_logic;
  gpio_led_s       : out   std_logic;
  gpio_led_w       : out   std_logic;
  gpio_sw_c        : in    std_logic;
  gpio_sw_e        : in    std_logic;
  gpio_sw_n        : in    std_logic;
  gpio_sw_s        : in    std_logic;
  gpio_sw_w        : in    std_logic;

  --Clock/Data connection to ADC on FMC150 (ADS62P49)
  clk_ab_p         : in    std_logic;
  clk_ab_n         : in    std_logic;
  cha_p            : in    std_logic_vector(6 downto 0);
  cha_n            : in    std_logic_vector(6 downto 0);
  chb_p            : in    std_logic_vector(6 downto 0);
  chb_n            : in    std_logic_vector(6 downto 0);

  --Clock/Data connection to DAC on FMC150 (DAC3283)
  dac_dclk_p       : out   std_logic;
  dac_dclk_n       : out   std_logic;
  dac_data_p       : out   std_logic_vector(7 downto 0);
  dac_data_n       : out   std_logic_vector(7 downto 0);
  dac_frame_p      : out   std_logic;
  dac_frame_n      : out   std_logic;
  txenable         : out   std_logic;

  --Clock/Trigger connection to FMC150
  clk_to_fpga_p    : in    std_logic;
  clk_to_fpga_n    : in    std_logic;
  ext_trigger_p    : in    std_logic;
  ext_trigger_n    : in    std_logic;

  --Serial Peripheral Interface (SPI)
  spi_sclk         : out   std_logic; -- Shared SPI clock line
  spi_sdata        : out   std_logic; -- Shared SPI sata line

  -- ADC specific signals
  adc_n_en         : out   std_logic; -- SPI chip select
  adc_sdo          : in    std_logic; -- SPI data out
  adc_reset        : out   std_logic; -- SPI reset

  -- CDCE specific signals
  cdce_n_en        : out   std_logic; -- SPI chip select
  cdce_sdo         : in    std_logic; -- SPI data out
  cdce_n_reset     : out   std_logic;
  cdce_n_pd        : out   std_logic;
  ref_en           : out   std_logic;
  pll_status       : in    std_logic;

  -- DAC specific signals
  dac_n_en         : out   std_logic; -- SPI chip select
  dac_sdo          : in    std_logic; -- SPI data out

  -- Monitoring specific signals
  mon_n_en         : out   std_logic; -- SPI chip select
  mon_sdo          : in    std_logic; -- SPI data out
  mon_n_reset      : out   std_logic;
  mon_n_int        : in    std_logic;

  --FMC Present status
  prsnt_m2c_l      : in    std_logic;
  
  --Signal Out
  out_i        	 : out 	std_logic_vector(15 downto 0);
  out_q        	 : out	std_logic_vector(15 downto 0)   
  
);
end ml605_fmc150;

architecture ml605_fmc150_syn of ml605_fmc150 is

----------------------------------------------------------------------------------------------------
-- Constant declaration
----------------------------------------------------------------------------------------------------
constant CLK_IDELAY : integer := 0; -- Initial number of delay taps on ADC clock input
constant CHA_IDELAY : integer := 0; -- Initial number of delay taps on ADC data port A
constant CHB_IDELAY : integer := 0; -- Initial number of delay taps on ADC data port B

-- Define the phase increment word for the DDC and DUC blocks (aka NCO)
-- dec2bin(round(Fc/Fs*2^28)), where Fc = -12 MHz, Fs = 61.44 MHz
--constant FREQ_DEFAULT : std_logic_vector(27 downto 0) := x"CE00000";
constant FREQ_DEFAULT : std_logic_vector(27 downto 0) := x"3200000";

----------------------------------------------------------------------------------------------------
-- Component declaration
----------------------------------------------------------------------------------------------------
component icon is
port (
  control0 : inout std_logic_vector(35 downto 0);
  control1 : inout std_logic_vector(35 downto 0);
  control2 : inout std_logic_vector(35 downto 0);
  control3 : inout std_logic_vector(35 downto 0)
--  control4 : inout std_logic_vector(35 downto 0)
--  control5 : inout std_logic_vector(35 downto 0)
--  control6 : inout std_logic_vector(35 downto 0)
--  control7 : inout std_logic_vector(35 downto 0)
);
end component icon;

component vio is
port (
  clk       : in    std_logic := 'X';
  sync_in   : in    std_logic_vector(75 downto 0);
  control   : inout std_logic_vector(35 downto 0);
  sync_out  : out   std_logic_vector(101 downto 0)
);
end component vio;

component ila is
port (
  clk     : in    std_logic := 'X';
  trig0   : in    std_logic_vector(31 downto 0);
  control : inout std_logic_vector(35 downto 0)
);
end component ila;

--component ila3 is
--	port (
--	 CONTROL: inout std_logic_vector(35 downto 0);
--	 CLK: in std_logic;
--	 TRIG0: in std_logic_vector(15 downto 0);
--	 TRIG1: in std_logic_vector(15 downto 0);
--	 TRIG2: in std_logic_vector(0 to 0);
--	 TRIG3: in std_logic_vector(27 downto 0);
--	 TRIG4: in std_logic_vector(0 to 0);
--	 TRIG5: in std_logic_vector(0 to 0);
--	 TRIG6: in std_logic_vector(0 to 0);
--	 TRIG7: in std_logic_vector(15 downto 0);
--	 TRIG8: in std_logic_vector(15 downto 0);
--	 TRIG9: in std_logic_vector(0 to 0);
--	 TRIG10: in std_logic_vector(0 to 0);
--	 TRIG11: in std_logic_vector(0 to 0)
--	);
--end component ila3;

component mmcm_adac is
port (
  -- Clock in ports
  clk_in1   : in  std_logic;
  -- Clock out ports
  clk_out1  : out std_logic;
  clk_out2  : out std_logic;
  clk_out3  : out std_logic;
  -- Status and control signals
  reset     : in  std_logic;
  locked    : out std_logic
);
end component mmcm_adac;

component mmcm is
port (
  -- Clock in ports
  clk_in1_p : in  std_logic;
  clk_in1_n : in  std_logic;
  -- Clock out ports
  clk_out1  : out std_logic;
  clk_out2  : out std_logic;
  -- Status and control signals
  reset     : in  std_logic;
  locked    : out std_logic
);
end component mmcm;

component fmc150_spi_ctrl is
port (
  -- VIO command interface
  rd_n_wr          : in    std_logic;
  addr             : in    std_logic_vector(15 downto 0);
  idata            : in    std_logic_vector(31 downto 0);
  odata            : out   std_logic_vector(31 downto 0);
  busy             : out   std_logic;

  cdce72010_valid  : in    std_logic;
  ads62p49_valid   : in    std_logic;
  dac3283_valid    : in    std_logic;
  amc7823_valid    : in    std_logic;

  external_clock   : in    std_logic;

  -- Global signals
  rst              : in    std_logic;
  clk              : in    std_logic;

  -- External signals
  spi_sclk         : out   std_logic;
  spi_sdata        : out   std_logic;

  adc_n_en         : out   std_logic;
  adc_sdo          : in    std_logic;
  adc_reset        : out   std_logic;

  cdce_n_en        : out   std_logic;
  cdce_sdo         : in    std_logic;
  cdce_n_reset     : out   std_logic;
  cdce_n_pd        : out   std_logic;
  ref_en           : out   std_logic;
  pll_status       : in    std_logic;

  dac_n_en         : out   std_logic;
  dac_sdo          : in    std_logic;

  mon_n_en         : out   std_logic;
  mon_sdo          : in    std_logic;
  mon_n_reset      : out   std_logic;
  mon_n_int        : in    std_logic;

  prsnt_m2c_l      : in    std_logic 

);
end component fmc150_spi_ctrl;

component Data IS
  PORT (
    clka : IN STD_LOGIC;
    ena : IN STD_LOGIC;
    addra : IN STD_LOGIC_VECTOR(8 DOWNTO 0);
    douta : OUT STD_LOGIC_VECTOR(5 DOWNTO 0)
  );
END component Data;

component OFDM_Tx
    Port ( clk : in  STD_LOGIC;
           ce : in  STD_LOGIC;
           rst : in  STD_LOGIC;
			  dataIn : in  STD_LOGIC_VECTOR (5 downto 0);
			  dataAvailable_in : in  STD_LOGIC;
			  dataInReady : out STD_LOGIC;
           I : out  STD_LOGIC_VECTOR (15 downto 0);
           Q : out  STD_LOGIC_VECTOR (15 downto 0)
	 );
end component;

component DDS
port (
  ce     : in std_logic;
  clk    : in std_logic;
  cosine : out std_logic_vector(15 downto 0);
  sine   : out std_logic_vector(15 downto 0)
);
end component;

component ddc_umts_v6 is
port (
  reset         : in  std_logic;
  clk           : in  std_logic;
  din_i         : in  std_logic_vector(15 downto 0);
  din_q         : in  std_logic_vector(15 downto 0);
  vin           : in  std_logic;
  freq          : in  std_logic_vector(27 downto 0);
  cmplx_aresetn : in  std_logic;
  dds_reset     : in  std_logic;
  dout_i        : out std_logic_vector(15 downto 0);
  dout_q        : out std_logic_vector(15 downto 0);
  vout          : out std_logic
);
end component;

component duc_umts_v6
port (
  reset         : in  std_logic;
  clk           : in  std_logic;
  din_i         : in  std_logic_vector(15 downto 0);
  din_q         : in  std_logic_vector(15 downto 0);
  vin           : in  std_logic;
  freq          : in  std_logic_vector(27 downto 0);
  dout_i        : out std_logic_vector(15 downto 0);
  dout_q        : out std_logic_vector(15 downto 0);
  vout          : out std_logic;
  cmplx_aresetn : out std_logic;
  dds_reset     : out std_logic
--  ila_duc_control_concat : inout std_logic_vector(179 downto 0)
);
end component;

----------------------------------------------------------------------------------------------------
-- Signal declaration
----------------------------------------------------------------------------------------------------
signal vio_sync_in       : std_logic_vector(75 downto 0);
signal vio_control       : std_logic_vector(35 downto 0);
signal vio_sync_out      : std_logic_vector(101 downto 0);
signal vio_sync_out_prev : std_logic_vector(101 downto 0);
signal sel : std_logic_vector(4 downto 0) := "00000";

signal ila_adc_clk       : std_logic;
signal ila_adc_trig0     : std_logic_vector(31 downto 0) := (others=>'0');
signal ila_adc_control   : std_logic_vector(35 downto 0) := (others=>'0');

signal ila_adc_dout_clk  : std_logic := '0';
signal ila_adc_dout_trig0     : std_logic_vector(31 downto 0) := (others=>'0');
signal ila_adc_dout_control   : std_logic_vector(35 downto 0) := (others=>'0');

signal ila_dac_clk       : std_logic;
signal ila_dac_trig0     : std_logic_vector(31 downto 0) := (others=>'0');
signal ila_dac_control   : std_logic_vector(35 downto 0) := (others=>'0');

signal ila_ofdm_trig0    : std_logic_vector(31 downto 0) := (others=>'0');
signal ila_ofdm_control	 : std_logic_vector(35 downto 0) := (others=>'0');

signal clk_100Mhz        : std_logic;
signal clk_200Mhz        : std_logic;
signal mmcm_locked       : std_logic;

signal arst              : std_logic;
signal rst               : std_logic;
signal rst_duc_ddc       : std_logic;

signal clk_ab_l          : std_logic;
signal clk_ab_dly        : std_logic;
signal clk_ab_i          : std_logic;

signal cha_ddr           : std_logic_vector(6 downto 0);  -- Double Data Rate
signal cha_ddr_dly       : std_logic_vector(6 downto 0);  -- Double Data Rate, Delayed
signal cha_sdr           : std_logic_vector(13 downto 0); -- Single Data Rate

signal chb_ddr           : std_logic_vector(6 downto 0);  -- Double Data Rate
signal chb_ddr_dly       : std_logic_vector(6 downto 0);  -- Double Data Rate, Delayed
signal chb_sdr           : std_logic_vector(13 downto 0); -- Single Data Rate

signal adc_dout_i        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z1        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z1        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z2        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z2        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z3        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z3        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z4        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z4        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z5        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z5        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z6        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z6        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z7        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z7        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z8        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z8        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z9        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z9        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z10        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z10        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z11        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z11        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z12        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z12        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z13        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z13        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z14        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z14        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z15        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z15        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z16        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z16        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z17        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z17        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z18        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z18        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z19        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z19        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z20        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z20        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z21        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z21        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z22        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z22        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z23        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z23        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z24        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z24        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z1_368_64        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z1_368_64        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_i_z2_368_64        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_dout_q_z2_368_64        : std_logic_vector(15 downto 0); -- Single Data Rate, Extended to 16-bit
signal adc_vout          : std_logic := '0';
signal adc_vout_z1          : std_logic := '0';
signal adc_vout_z2          : std_logic := '0';
signal adc_vout_z3          : std_logic := '0';
signal adc_vout_z4          : std_logic := '0';
signal adc_vout_z5          : std_logic := '0';
signal adc_vout_z6          : std_logic := '0';
signal adc_vout_z7          : std_logic := '0';
signal adc_vout_z8          : std_logic := '0';
signal adc_vout_z9          : std_logic := '0';
signal adc_vout_z10          : std_logic := '0';
signal adc_vout_z11          : std_logic := '0';
signal adc_vout_z12          : std_logic := '0';

signal freq              : std_logic_vector(27 downto 0);
signal cmplx_aresetn_duc : std_logic;
signal dds_reset_duc     : std_logic;
signal cmplx_aresetn_ddc : std_logic;
signal dds_reset_ddc     : std_logic;

signal ddc_din_i         : std_logic_vector(15 downto 0);
signal ddc_din_q         : std_logic_vector(15 downto 0);
signal ddc_vin           : std_logic := '0';
--signal ddc_vin_z1           : std_logic := '0';
--signal ddc_vin_z2           : std_logic := '0';
--signal ddc_vin_z3           : std_logic := '0';
--signal ddc_vin_z4           : std_logic := '0';
--signal ddc_vin_z5           : std_logic := '0';
signal ddc_dout_i_tmp    : std_logic_vector(15 downto 0);
signal ddc_dout_q_tmp    : std_logic_vector(15 downto 0);
signal ddc_vout_tmp      : std_logic;
signal ddc_dout_i        : std_logic_vector(15 downto 0);
signal ddc_dout_q        : std_logic_vector(15 downto 0);
signal ddc_vout          : std_logic;

signal duc_din_i         : std_logic_vector(15 downto 0);
signal duc_din_q         : std_logic_vector(15 downto 0);
signal duc_vin           : std_logic;
signal duc_dout_i        : std_logic_vector(15 downto 0);
signal duc_dout_q        : std_logic_vector(15 downto 0);
signal duc_vout          : std_logic := '0';
signal sig_ila_duc_control_concat : std_logic_vector(179 downto 0);

signal signal_ce         : std_logic;
signal signal_ce_prev    : std_logic;
signal signal_vout       : std_logic;

signal ofdm_to_duc_i		 : std_logic_vector(15 downto 0);
signal ofdm_to_duc_q		 : std_logic_vector(15 downto 0);

signal sine              : std_logic_vector(15 downto 0);
signal cosine            : std_logic_vector(15 downto 0);
signal dds_to_duc_i      : std_logic_vector(15 downto 0);
signal dds_to_duc_q      : std_logic_vector(15 downto 0);

signal ofdm_dds_mux_to_duc_i     : std_logic_vector(15 downto 0);
signal ofdm_dds_mux_to_duc_q     : std_logic_vector(15 downto 0);

signal imp_dout_i        : std_logic_vector(15 downto 0);
signal imp_dout_q        : std_logic_vector(15 downto 0);

signal delay_update      : std_logic;
signal clk_cntvaluein    : std_logic_vector(4 downto 0);
signal cha_cntvaluein    : std_logic_vector(4 downto 0) := "11111";
signal chb_cntvaluein    : std_logic_vector(4 downto 0) := "11111";

signal clk_cntvalueout   : std_logic_vector(4 downto 0);
type cha_cntvalueout_array is array(cha_p'length-1 downto 0) of std_logic_vector(4 downto 0);
signal cha_cntvalueout   : cha_cntvalueout_array;
type chb_cntvalueout_array is array(chb_p'length-1 downto 0) of std_logic_vector(4 downto 0);
signal chb_cntvalueout   : chb_cntvalueout_array;

signal rd_n_wr           : std_logic;
signal addr              : std_logic_vector(15 downto 0);
signal idata             : std_logic_vector(31 downto 0);
signal odata             : std_logic_vector(31 downto 0);
signal busy              : std_logic;
signal cdce72010_valid   : std_logic;
signal ads62p49_valid    : std_logic;
signal dac3283_valid     : std_logic;
signal amc7823_valid     : std_logic;

signal clk_61_44MHz      : std_logic;
signal clk_122_88MHz     : std_logic;
signal clk_368_64MHz     : std_logic;
signal mmcm_adac_locked  : std_logic;

signal clk_to_fpga       : std_logic;

signal dac_din_i         : std_logic_vector(15 downto 0);
signal dac_din_q         : std_logic_vector(15 downto 0);

signal frame             : std_logic;
signal io_rst            : std_logic;

signal dac_dclk_prebuf   : std_logic;
signal dac_data_prebuf   : std_logic_vector(7 downto 0);
signal dac_frame_prebuf  : std_logic;

signal digital_mode      : std_logic;
signal ddc_duc_bypass    : std_logic;
signal external_clock    : std_logic;

signal debounce_rst      : std_logic;
signal debounce_cnt      : std_logic_vector(15 downto 0) := (others => '0');

signal sig_temp_debug_i  : std_logic_vector(15 downto 0) := (others => '0');
signal sig_temp_debug_q  : std_logic_vector(15 downto 0) := (others => '0');

signal sig_TxDataAddr : std_logic_vector(8 downto 0) := (others => '0');
signal sig_TxData  : std_logic_vector(5 downto 0) := (others => '0');
signal sig_TxDataAvailable	: std_logic := '0';
signal sig_ofdmDataInReady	: std_logic := '0';
	
----------------------------------------------------------------------------------------------------
-- Begin
----------------------------------------------------------------------------------------------------
begin

----------------------------------------------------------------------------------------------------
-- ICON
----------------------------------------------------------------------------------------------------
icon_inst : icon
port map (
  control0 => vio_control,
  control1 => ila_adc_control,
  control2 => ila_dac_control,
  control3 => ila_ofdm_control  
--  control5 => ila_debug_ofdmTx
--  control6 => sig_ila_duc_control_concat(71 downto 36),
--  control7 => sig_ila_duc_control_concat(35 downto 0)
);

----------------------------------------------------------------------------------------------------
-- VIO
----------------------------------------------------------------------------------------------------
vio_inst : vio
port map (
  clk       => clk_100Mhz,
  sync_in   => vio_sync_in,
  control   => vio_control,
  sync_out  => vio_sync_out
);

----------------------------------------------------------------------------------
-- VIO In Mapping
----------------------------------------------------------------------------------

vio_sync_in <=
  busy               & -- (75 downto 75)
  odata              & -- (74 downto 43)
  freq               & -- (42 downto 15)
  clk_cntvalueout    & -- (14 downto 10)
  chb_cntvalueout(0) & -- (09 downto 05)
  cha_cntvalueout(0);  -- (04 downto 00)

----------------------------------------------------------------------------------
-- VIO Out Mapping
----------------------------------------------------------------------------------

process (arst, clk_100Mhz)
begin
  if (arst = '1') then
    delay_update   <= '1';
    clk_cntvaluein <= conv_std_logic_vector(CLK_IDELAY, 5);
    cha_cntvaluein <= conv_std_logic_vector(CHA_IDELAY, 5);
    chb_cntvaluein <= conv_std_logic_vector(CHB_IDELAY, 5);
    freq           <= FREQ_DEFAULT;
  elsif (rising_edge(clk_100Mhz)) then
    -- Register the VIO output in order to detect changes
    vio_sync_out_prev <= vio_sync_out;

    -- Generate an delay_update pulse in case one of the cntvaluein values has changed
    if (vio_sync_out(4 downto 0) /= vio_sync_out_prev(4 downto 0)) then
      delay_update   <= '1';
      clk_cntvaluein <= clk_cntvaluein;
      chb_cntvaluein <= chb_cntvaluein;
      cha_cntvaluein <= vio_sync_out(4 downto 0);
    elsif (vio_sync_out(9 downto 5) /= vio_sync_out_prev(9 downto 5)) then
      delay_update   <= '1';
      clk_cntvaluein <= clk_cntvaluein;
      chb_cntvaluein <= vio_sync_out(9 downto 5);
      cha_cntvaluein <= cha_cntvaluein;
    elsif (vio_sync_out(14 downto 10) /= vio_sync_out_prev(14 downto 10)) then
      delay_update   <= '1';
      clk_cntvaluein <= vio_sync_out(14 downto 10);
      chb_cntvaluein <= chb_cntvaluein;
      cha_cntvaluein <= cha_cntvaluein;
    else
      delay_update   <= '0';
      clk_cntvaluein <= clk_cntvaluein;
      chb_cntvaluein <= chb_cntvaluein;
      cha_cntvaluein <= cha_cntvaluein;
    end if;

    -- Overrule the default freq setting
    if (vio_sync_out(15) = '1') then
      freq <= vio_sync_out(43 downto 16);
    else
      freq <= FREQ_DEFAULT;
    end if;

  end if;
end process;

-- FMC150 settings control interface
addr            <= vio_sync_out(59 downto 44);
idata           <= vio_sync_out(91 downto 60);
rd_n_wr         <= vio_sync_out(92);
cdce72010_valid <= vio_sync_out(93);
ads62p49_valid  <= vio_sync_out(94);
dac3283_valid   <= vio_sync_out(95);
amc7823_valid   <= vio_sync_out(96);
sel   <= vio_sync_out(101 downto 97);						

----------------------------------------------------------------------------------------------------
-- ILA_OFDM_Tx out
----------------------------------------------------------------------------------------------------

ila_ofdmTx : ila
port map (
  clk     => signal_ce, --clk_61_44MHz,
  trig0   => ila_ofdm_trig0,
  control => ila_ofdm_control
);

ila_ofdm_trig0 <= ofdm_dds_mux_to_duc_q & ofdm_dds_mux_to_duc_i;

----------------------------------------------------------------------------------------------------
-- ILA DAC
----------------------------------------------------------------------------------------------------
ila_dac_inst : ila
port map (
  clk     => ila_dac_clk,
  trig0   => ila_dac_trig0,
  control => ila_dac_control
);

-- ILA Mapping
ila_dac_clk <= clk_61_44MHz;
ila_dac_trig0 <= dac_din_q & dac_din_i;

----------------------------------------------------------------------------------------------------
-- ILA ADC_out
----------------------------------------------------------------------------------------------------

--ila_adc_out_inst : ila
--port map (
--  clk     => ila_adc_dout_clk,
--  trig0   => ila_adc_dout_trig0,
--  control => ila_adc_dout_control
--);
--
--ila_adc_dout_clk <= clk_368_64MHz;
--ila_adc_dout_trig0 <= adc_dout_q & adc_dout_i;

----------------------------------------------------------------------------------------------------
-- ILA DDC_all
----------------------------------------------------------------------------------------------------

--ila_ddc_all : ila3
--port map (
--	 CONTROL => ila_ddc_all_control,
--	 CLK => ila_ddc_all_clk,
--	 TRIG0 => ila_ddc_all_trig0,
--	 TRIG1 => ila_ddc_all_trig1,
--	 TRIG2 => ila_ddc_all_trig2,
--	 TRIG3 => ila_ddc_all_trig3,
--	 TRIG4 => ila_ddc_all_trig4,
--	 TRIG5 => ila_ddc_all_trig5,
--	 TRIG6 => ila_ddc_all_trig6,
--	 TRIG7 => ila_ddc_all_trig7,
--	 TRIG8 => ila_ddc_all_trig8,
--	 TRIG9 => ila_ddc_all_trig9,
--	 TRIG10 => ila_ddc_all_trig10,
--	 TRIG11 => ila_ddc_all_trig11
--);

--ila_ddc_all_clk <= clk_368_64MHz;
--ila_ddc_all_trig0 <= ddc_din_i;
--ila_ddc_all_trig1 <= ddc_din_q;
--ila_ddc_all_trig2 <= (0 => dds_reset_ddc);
--ila_ddc_all_trig3 <= freq;
--ila_ddc_all_trig4 <= (0 => rst_duc_ddc);
--ila_ddc_all_trig5 <= (0 => ddc_vin);
--ila_ddc_all_trig6 <= (0 => cmplx_aresetn_ddc);
--ila_ddc_all_trig7 <= ddc_dout_i;
--ila_ddc_all_trig8 <= ddc_dout_q;
--ila_ddc_all_trig9 <= (0 => ddc_vout);
--ila_ddc_all_trig10 <= (0 => clk_122_88MHz);
--ila_ddc_all_trig11 <= (0 => clk_61_44MHz);
	 
----------------------------------------------------------------------------------------------------
-- ILA DDC_out
----------------------------------------------------------------------------------------------------
ila_adc_inst : ila
port map (
  clk     => ila_adc_clk,
  trig0   => ila_adc_trig0,
  control => ila_adc_control
);

-- ILA Mapping
ila_adc_clk <= ddc_vout;
ila_adc_trig0 <= ddc_dout_q & ddc_dout_i;

----------------------------------------------------------------------------------------------------
-- MMCM System Clock
----------------------------------------------------------------------------------------------------
mmcm_inst : mmcm
port map (
  clk_in1_p => sysclk_p,
  clk_in1_n => sysclk_n,
  clk_out1  => clk_100Mhz,
  clk_out2  => clk_200Mhz,
  reset     => cpu_reset,
  locked    => mmcm_locked
);

arst <= not mmcm_locked;

----------------------------------------------------------------------------------------------------
-- Clock from ADC on FMC150 for channel A and B
----------------------------------------------------------------------------------------------------

-- Differential input buffer
ibufds_inst : ibufds
generic map (
  IOSTANDARD => "LVDS_25",
  DIFF_TERM  => TRUE
)
port map (
  i  => clk_ab_p,
  ib => clk_ab_n,
  o  => clk_ab_l
);

-- Input delay
iodelay_inst : iodelaye1
generic map (
  IDELAY_TYPE    => "VAR_LOADABLE",
  IDELAY_VALUE   => CLK_IDELAY,
  SIGNAL_PATTERN => "CLOCK",
  DELAY_SRC      => "I"
)
port map (
  idatain     => clk_ab_l,
  dataout     => clk_ab_dly,
  c           => clk_100MHz,
  ce          => '0',
  inc         => '0',
  datain      => '0',
  odatain     => '0',
  clkin       => '0',
  rst         => delay_update,
  cntvaluein  => clk_cntvaluein,
  cntvalueout => clk_cntvalueout,
  cinvctrl    => '0',
  t           => '1'
);

-- Make sure the clock is routed on a global net
bufg_inst : bufg
port map (
  i  => clk_ab_dly,
  o  => clk_ab_i
);

----------------------------------------------------------------------------------------------------
-- MMCM ADC / DAC Clocks
----------------------------------------------------------------------------------------------------
mmcm_adac_inst : mmcm_adac
port map (
  clk_in1   => clk_ab_i,
  clk_out1  => clk_61_44MHz,
  clk_out2  => clk_122_88MHz,
  clk_out3  => clk_368_64MHz,
  reset     => cpu_reset,
  locked    => mmcm_adac_locked
);

----------------------------------------------------------------------------------------------------
-- Reset sequence
----------------------------------------------------------------------------------------------------
process (mmcm_adac_locked, clk_61_44MHz)
  variable cnt : integer range 0 to 1023 := 0;
begin
  if (mmcm_adac_locked = '0') then

    cnt := 0;
    rst <= '1';
    io_rst <= '0';
    frame <= '0';
    txenable <= '0';

  elsif (rising_edge(clk_61_44MHz)) then

    -- DDC and DUC are kept in reset state for a while...
    if (cnt < 1023) then
      cnt := cnt + 1;
      rst <= '1';
    else
      cnt := cnt;
      rst <= '0';
    end if;

    -- The OSERDES blocks are synchronously reset for one clock cycle...
    if (cnt = 255) then
      io_rst <= '1';
    else
      io_rst <= '0';
    end if;

    -- Then a frame pulse is transmitted to the DAC...
    if (cnt = 511) then
      frame <= '1';
    else
      frame <= '0';
    end if;

    -- Finally the TX enable for the DAC can by pulled high.
    if (cnt = 1023) then
      txenable <= '1';
    end if;

  end if;
end process;

----------------------------------------------------------------------------------------------------
-- Channel A data from ADC
----------------------------------------------------------------------------------------------------
adc_data_a: for i in 0 to 6 generate

  -- Differantial input buffer with termination (LVDS)
  ibufds_inst : ibufds
  generic map (
    IOSTANDARD => "LVDS_25",
    DIFF_TERM  => TRUE
  )
  port map (
    i  => cha_p(i),
    ib => cha_n(i),
    o  => cha_ddr(i)
  );

  -- Input delay
  iodelay_inst : iodelaye1
  generic map (
    IDELAY_TYPE    => "VAR_LOADABLE",
    IDELAY_VALUE   => CHA_IDELAY,
    SIGNAL_PATTERN => "DATA",
    DELAY_SRC      => "I"
  )
  port map (
    idatain     => cha_ddr(i),
    dataout     => cha_ddr_dly(i),
    c           => clk_100MHz,
    ce          => '0',
    inc         => '0',
    datain      => '0',
    odatain     => '0',
    clkin       => '0',
    rst         => delay_update,
    cntvaluein  => cha_cntvaluein,
    cntvalueout => cha_cntvalueout(i),
    cinvctrl    => '0',
    t           => '1'
  );

  -- DDR to SDR
  iddr_inst : iddr
  generic map (
    DDR_CLK_EDGE => "SAME_EDGE_PIPELINED"
  )
  port map (
    q1 => cha_sdr(2*i),
    q2 => cha_sdr(2*i+1),
    c  => clk_61_44MHz,
    ce => '1',
    d  => cha_ddr_dly(i),
    r  => '0',
    s  => '0'
  );

end generate;

----------------------------------------------------------------------------------------------------
-- Channel B data from ADC
----------------------------------------------------------------------------------------------------
adc_data_b: for i in 0 to 6 generate

  -- Differantial input buffer with termination (LVDS)
  ibufds_inst : ibufds
  generic map (
    IOSTANDARD => "LVDS_25",
    DIFF_TERM  => TRUE
  )
  port map (
    i  => chb_p(i),
    ib => chb_n(i),
    o  => chb_ddr(i)
  );

  -- Input delay
  iodelay_inst : iodelaye1
  generic map (
    IDELAY_TYPE    => "VAR_LOADABLE",
    IDELAY_VALUE   => CHB_IDELAY,
    SIGNAL_PATTERN => "DATA",
    DELAY_SRC      => "I"
  )
  port map (
    idatain     => chb_ddr(i),
    dataout     => chb_ddr_dly(i),
    c           => clk_100MHz,
    ce          => '0',
    inc         => '0',
    datain      => '0',
    odatain     => '0',
    clkin       => '0',
    rst         => delay_update,
    cntvaluein  => chb_cntvaluein,
    cntvalueout => chb_cntvalueout(i),
    cinvctrl    => '0',
    t           => '1'
  );

  -- DDR to SDR
  iddr_inst : iddr
  generic map (
    DDR_CLK_EDGE => "SAME_EDGE_PIPELINED"
  )
  port map (
    q1 => chb_sdr(2*i),
    q2 => chb_sdr(2*i+1),
    c  => clk_61_44MHz,
    ce => '1',
    d  => chb_ddr_dly(i),
    r  => '0',
    s  => '0'
  );

end generate;

----------------------------------------------------------------------------------------------------
-- Extend to 16-bit
----------------------------------------------------------------------------------------------------
process (clk_61_44MHz)
begin
  if (rising_edge(clk_61_44MHz)) then

    -- Left justify the data of both channels on 16-bits
    adc_dout_i <= cha_sdr & "00";
    adc_dout_q <= chb_sdr & "00";

		adc_dout_i_z1 <= adc_dout_i;
		adc_dout_q_z1 <= adc_dout_q;
		
		adc_dout_i_z2 <= adc_dout_i_z1;
		adc_dout_q_z2 <= adc_dout_q_z1;
		
		adc_dout_i_z3 <= adc_dout_i_z2;
		adc_dout_q_z3 <= adc_dout_q_z2;
	
--		adc_dout_i_z4 <= adc_dout_i_z3;
--		adc_dout_q_z4 <= adc_dout_q_z3;
--	
--		adc_dout_i_z5 <= adc_dout_i_z4;
--		adc_dout_q_z5 <= adc_dout_q_z4;
--	
--		adc_dout_i_z6 <= adc_dout_i_z5;
--		adc_dout_q_z6 <= adc_dout_q_z5;
--	
--		adc_dout_i_z7 <= adc_dout_i_z6;
--		adc_dout_q_z7 <= adc_dout_q_z6;
--	
--		adc_dout_i_z8 <= adc_dout_i_z7;
--		adc_dout_q_z8 <= adc_dout_q_z7;
--		
--		adc_dout_i_z9 <= adc_dout_i_z8;
--		adc_dout_q_z9 <= adc_dout_q_z8;
--		
--		adc_dout_i_z10 <= adc_dout_i_z9;
--		adc_dout_q_z10 <= adc_dout_q_z9;
--		
--		adc_dout_i_z11 <= adc_dout_i_z10;
--		adc_dout_q_z11 <= adc_dout_q_z10;
--		
--		adc_dout_i_z12 <= adc_dout_i_z11;
--		adc_dout_q_z12 <= adc_dout_q_z11;
--		
--		adc_dout_i_z13 <= adc_dout_i_z12;
--		adc_dout_q_z13 <= adc_dout_q_z12;
--		
--		adc_dout_i_z14 <= adc_dout_i_z13;
--		adc_dout_q_z14 <= adc_dout_q_z13;
--		
--		adc_dout_i_z15 <= adc_dout_i_z14;
--		adc_dout_q_z15 <= adc_dout_q_z14;
--		
--		adc_dout_i_z16 <= adc_dout_i_z15;
--		adc_dout_q_z16 <= adc_dout_q_z15;
--
--		adc_dout_i_z17 <= adc_dout_i_z16;
--		adc_dout_q_z17 <= adc_dout_q_z16;
--
--		adc_dout_i_z18 <= adc_dout_i_z17;
--		adc_dout_q_z18 <= adc_dout_q_z17;
--
--		adc_dout_i_z19 <= adc_dout_i_z18;
--		adc_dout_q_z19 <= adc_dout_q_z18;
--
--		adc_dout_i_z20 <= adc_dout_i_z19;
--		adc_dout_q_z20 <= adc_dout_q_z19;
--
--		adc_dout_i_z21 <= adc_dout_i_z20;
--		adc_dout_q_z21 <= adc_dout_q_z20;
--
--		adc_dout_i_z22 <= adc_dout_i_z21;
--		adc_dout_q_z22 <= adc_dout_q_z21;
--
--		adc_dout_i_z23 <= adc_dout_i_z22;
--		adc_dout_q_z23 <= adc_dout_q_z22;
--		
--		adc_dout_i_z24 <= adc_dout_i_z23;
--		adc_dout_q_z24 <= adc_dout_q_z23;
				
  end if;
end process;

----------------------------------------------------------------------------------------------------
-- Generate a valid signal to the DDC every 6th clock cycle
----------------------------------------------------------------------------------------------------
process (clk_368_64MHz)
  variable cnt : integer range 0 to 5 := 0;
begin
  if (rising_edge(clk_368_64MHz)) then

    if (cnt = 5) then
      adc_vout <= '1';
      cnt := 0;
    else
      adc_vout <= '0';
      cnt := cnt + 1;
    end if;

  end if;
end process;

----------------------------------------------------------------------------------------------------
-- Input MUX - Select data connected to the DDC
----------------------------------------------------------------------------------------------------
process (clk_368_64MHz)
begin
  if (rising_edge(clk_368_64MHz)) then
	adc_vout_z1 <= adc_vout;
	adc_vout_z2 <= adc_vout_z1;
	adc_vout_z3 <= adc_vout_z2;
	adc_vout_z4 <= adc_vout_z3;
	adc_vout_z5 <= adc_vout_z4;
	adc_vout_z6 <= adc_vout_z5;
--	adc_vout_z7 <= adc_vout_z6;
--	adc_vout_z8 <= adc_vout_z7;
--	adc_vout_z9 <= adc_vout_z8;
--	adc_vout_z10 <= adc_vout_z9;
--	adc_vout_z11 <= adc_vout_z10;
--	adc_vout_z12 <= adc_vout_z11;

--		case sel is
--			when "00000" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i;
--				adc_dout_q_z1_368_64 <= adc_dout_q;			
--			when "00001" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z1;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z1;		
--			when "00010" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z2;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z2;	
--			when "00011" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z3;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z3;	
--			when "00100" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z4;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z4;	
--			when "00101" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z5;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z5;	
--			when "00110" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z6;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z6;	
--			when "00111" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z7;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z7;	
--			when "01000" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z8;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z8;	
--			when "01001" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z9;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z9;	
--			when "01010" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z10;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z10;	
--			when "01011" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z11;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z11;	
--			when "01100" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z12;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z12;	
--			when "01101" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z13;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z13;	
--			when "01110" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z14;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z14;	
--			when "01111" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z15;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z15;
--			when "10000" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z16;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z16;
--			when "10001" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z17;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z17;
--			when "10010" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z18;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z18;
--			when "10011" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z19;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z19;
--			when "10100" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z20;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z20;
--			when "10101" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z21;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z21;
--			when "10110" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z22;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z22;
--			when "10111" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z23;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z23;
--			when "11000" =>
--				adc_dout_i_z1_368_64 <= adc_dout_i_z24;
--				adc_dout_q_z1_368_64 <= adc_dout_q_z24;				
--			when others =>
--				adc_dout_i_z1_368_64 <= adc_dout_i;
--				adc_dout_q_z1_368_64 <= adc_dout_q;				
--		end case;
		
	adc_dout_i_z1_368_64 <= adc_dout_i_z3;
	adc_dout_q_z1_368_64 <= adc_dout_q_z3;
	
	adc_dout_i_z2_368_64 <= adc_dout_i_z1_368_64;
	adc_dout_q_z2_368_64 <= adc_dout_q_z1_368_64;	

    -- In digital mode connect the DUC output to the DDC input
    if (digital_mode = '1') then
      ddc_vin   <= duc_vout;
      ddc_din_i <= duc_dout_i;
      ddc_din_q <= duc_dout_q;
    -- In converter loopback mode connect the ADC outputs to the DDC input
    else	 	
      ddc_vin   <= adc_vout_z6;
      ddc_din_i <= adc_dout_i_z2_368_64;
      ddc_din_q <= adc_dout_q_z2_368_64;
    end if;

    cmplx_aresetn_ddc <= cmplx_aresetn_duc;
    dds_reset_ddc     <= dds_reset_duc;

  end if;
end process;

--ddc_vin   <= duc_vout   when digital_mode = '1' else adc_vout;
--ddc_din_i <= duc_dout_i when digital_mode = '1' else adc_dout_i;
--ddc_din_q <= duc_dout_q when digital_mode = '1' else adc_dout_q;

----------------------------------------------------------------------------------------------------
-- DDC - Digital Down Conversion
----------------------------------------------------------------------------------------------------
ddc_umts_v6_inst : ddc_umts_v6
port map (
  reset         => rst_duc_ddc,
  clk           => clk_368_64MHz,
  din_i         => ddc_din_i,
  din_q         => ddc_din_q,
  vin           => ddc_vin,
  freq          => freq,
  cmplx_aresetn => cmplx_aresetn_ddc,
  dds_reset     => dds_reset_ddc,
  dout_i        => ddc_dout_i_tmp,
  dout_q        => ddc_dout_q_tmp,
  vout          => ddc_vout_tmp
);

-- Output register
process (clk_368_64MHz)
begin
  if (rising_edge(clk_368_64MHz)) then

    ddc_dout_i <= ddc_dout_i_tmp;
    ddc_dout_q <= ddc_dout_q_tmp;
    ddc_vout   <= ddc_vout_tmp;

	 out_i		<= ddc_dout_i;
	 out_q		<= ddc_dout_q;
	 
  end if;
end process;

----------------------------------------------------------------------------------------------------
-- Signal generation
----------------------------------------------------------------------------------------------------
-- Two type of signals are generates:
--  a.  quadrature sinusoid from DDS
--  b.  impulse stimulus
-- The sample duration is 96-clock input sample period
----------------------------------------------------------------------------------------------------

process (clk_61_44MHz)
  variable cnt : integer range 0 to 47 := 0;
begin
  if (rising_edge(clk_61_44MHz)) then

    if (cnt = 15) then
      signal_ce <= '1';
      cnt := 0;
    else
      signal_ce <= '0';
      cnt := cnt + 1;
    end if;

  end if;
end process;

process (clk_368_64MHz)
begin
  if (rising_edge(clk_368_64MHz)) then

    signal_ce_prev <= signal_ce;

    if (signal_ce = '1' and signal_ce_prev = '0') then
      signal_vout <= '1';
     else
      signal_vout <= '0';
    end if;

    if (debounce_rst = '1') then
      rst_duc_ddc <= '1';
    elsif (signal_vout = '1') then
      rst_duc_ddc <= '0';
    end if;

  end if;
end process;

----------------------------------------------------------------------------------------------------
-- DATA
----------------------------------------------------------------------------------------------------

DataTx : Data
  PORT map (
    clka => clk_61_44MHz,
    ena => signal_ce and sig_ofdmDataInReady,
    addra => sig_TxDataAddr,
    douta => sig_TxData
  );

----------------------------------------------------------------------------------
-- OFDM transmitter
----------------------------------------------------------------------------------

ofdmTx : OFDM_Tx
port map(		  
	clk   => clk_61_44MHz,
	ce    => signal_ce,
	rst	=> '0',
	dataIn => sig_TxData,
	dataAvailable_in => sig_TxDataAvailable,
	dataInReady => sig_ofdmDataInReady,
	I   	=> ofdm_to_duc_i,
	Q 		=> ofdm_to_duc_q
);

----------------------------------------------------------------------------------
-- A) DDS generating a 384kHz signal based on a 3.84Msps sample clock.
----------------------------------------------------------------------------------

DDS_inst : DDS
port map (
  ce     => signal_ce,
  clk    => clk_61_44MHz,
  cosine => dds_to_duc_q,
  sine   => dds_to_duc_i
);

----------------------------------------------------------------------------------
-- B) Impulse stimulus
process(rst, clk_61_44MHz)
begin
  if (rst = '1') then

    debounce_rst <= '1';
    debounce_cnt <= (others => '0');

  elsif (rising_edge(clk_61_44MHz)) then

    if (signal_ce = '1') then

      -- start of reset debounce pulse, approx. 1 second
      if (gpio_sw_c = '1') then
        debounce_cnt <= (others => '0');
        debounce_rst <= '1';
      elsif (debounce_cnt = "0000000001111101") then
        debounce_cnt <= debounce_cnt + '1';
        debounce_rst <= '0';
      elsif (debounce_cnt < "0000000001111111") then
        debounce_cnt <= debounce_cnt + '1';
        debounce_rst <= debounce_rst;
      else
        debounce_cnt <= debounce_cnt;
        debounce_rst <= debounce_rst;
      end if;

      -- drive impulse into real input port
      if (debounce_cnt = "0000000001111110") then
        imp_dout_i <= "0100000000000000";
        imp_dout_q <= (others => '0');
      else
        imp_dout_i <= (others => '0');
        imp_dout_q <= (others => '0');
      end if;

    end if;

  end if;
end process;

----------------------------------------------------------------------------------------------------
-- Signal MUX - Select data connected to the DUC
----------------------------------------------------------------------------------------------------
process (clk_368_64MHz)
begin
  if (rising_edge(clk_368_64MHz)) then

    -- In digital mode connect the impulse signal to the DUC input
    if (digital_mode = '1') then
      duc_din_i <= imp_dout_i;
      duc_din_q <= imp_dout_q;
    -- In converter loopback mode connect the DDS output to the DUC input
    else
      duc_din_i <= ofdm_dds_mux_to_duc_i;
      duc_din_q <= ofdm_dds_mux_to_duc_q;
    end if;

  end if;
end process;

duc_vin <= signal_vout;

----------------------------------------------------------------------------------------------------
-- DUC - Digital Up Conversion
----------------------------------------------------------------------------------------------------
duc_umts_v6_inst : duc_umts_v6
port map (
  reset         => rst_duc_ddc,
  clk           => clk_368_64MHz,
  din_i         => ofdm_dds_mux_to_duc_i,
  din_q         => ofdm_dds_mux_to_duc_q,
  vin           => duc_vin,
  freq          => freq,
  dout_i        => duc_dout_i,
  dout_q        => duc_dout_q,
  vout          => duc_vout,
  cmplx_aresetn => cmplx_aresetn_duc,
  dds_reset     => dds_reset_duc
--  ila_duc_control_concat => sig_ila_duc_control_concat
);

----------------------------------------------------------------------------------------------------
-- Output MUX - Select data connected to the physical DAC interface
----------------------------------------------------------------------------------------------------
process (clk_61_44MHz)
begin
  if (rising_edge(clk_61_44MHz)) then

    -- If DDC and DUC is bypassed connect the ADC outputs to the DAC inputs
    if (ddc_duc_bypass = '1') then
      dac_din_i <= adc_dout_i;
      dac_din_q <= adc_dout_q;
    -- If DDC and DUC is used connect the DUC output to the DAC inputs
    else
      dac_din_i <= duc_dout_i;
      dac_din_q <= duc_dout_q;
    end if;

  end if;
end process;

----------------------------------------------------------------------------------------------------
-- DAC Reference Clock Input
----------------------------------------------------------------------------------------------------
-- clk_to_fpga_p/n is an additional LVDS clock from the CDCE72010, but currently not used in this
-- reference design. This additional clock might be used in applications where the ADC is not used
-- and a reference clock for the DAC is required.
----------------------------------------------------------------------------------------------------
ibufds_ref_clk : ibufds
generic map (
  IOSTANDARD => "LVDS_25",
  DIFF_TERM => TRUE
)
port map (
  i  => clk_to_fpga_p,
  ib => clk_to_fpga_n,
  o  => clk_to_fpga
);

----------------------------------------------------------------------------------------------------
-- Output serdes and LVDS buffer for DAC clock
----------------------------------------------------------------------------------------------------
oserdes_clock : oserdes
generic map (
  DATA_RATE_OQ => "DDR",
  DATA_RATE_TQ => "DDR",
  DATA_WIDTH => 4,
  INIT_OQ => '0',
  INIT_TQ => '0',
  SERDES_MODE => "MASTER",
  SRVAL_OQ => '0',
  SRVAL_TQ => '0',
  TRISTATE_WIDTH => 1
)
port map (
  oq        => dac_dclk_prebuf,
  shiftout1 => open,
  shiftout2 => open,
  tq        => open,
  clk       => clk_122_88MHz,
  clkdiv    => clk_61_44MHz,
  d1        => '1',
  d2        => '0',
  d3        => '1',
  d4        => '0',
  d5        => '0',
  d6        => '0',
  oce       => '1',
  rev       => '0',
  shiftin1  => '0',
  shiftin2  => '0',
  sr        => io_rst,
  t1        => '0',
  t2        => '0',
  t3        => '0',
  t4        => '0',
  tce       => '0'
);

--output buffer
obufds_clock : obufds_lvdsext_25
port map (
  i  => dac_dclk_prebuf,
  o  => dac_dclk_p,
  ob => dac_dclk_n
);

----------------------------------------------------------------------------------------------------
-- Output serdes and LVDS buffers for DAC data
----------------------------------------------------------------------------------------------------
dac_data: for i in 0 to 7 generate

  --oserdes in data path
  oserdes_data : oserdes
  generic map (
    DATA_RATE_OQ => "DDR",
    DATA_RATE_TQ => "DDR",
    DATA_WIDTH => 4,
    INIT_OQ => '0',
    INIT_TQ => '0',
    SERDES_MODE => "MASTER",
    SRVAL_OQ => '0',
    SRVAL_TQ => '0',
    TRISTATE_WIDTH => 1
  )
  port map (
    oq        => dac_data_prebuf(i),
    shiftout1 => open,
    shiftout2 => open,
    tq        => open,
    clk       => clk_122_88MHz,
    clkdiv    => clk_61_44MHz,
    d1        => dac_din_i(i + 8),
    d2        => dac_din_i(i),
    d3        => dac_din_q(i + 8),
    d4        => dac_din_q(i),
    d5        => '0',
    d6        => '0',
    oce       => '1',
    rev       => '0',
    shiftin1  => '0',
    shiftin2  => '0',
    sr        => io_rst,
    t1        => '0',
    t2        => '0',
    t3        => '0',
    t4        => '0',
    tce       => '0'
  );

  --output buffers
  obufds_data : obufds_lvdsext_25
  port map (
    i  => dac_data_prebuf(i),
    o  => dac_data_p(i),
    ob => dac_data_n(i)
  );

end generate;

--process (clk_61_44MHz)
--begin 
--	if (rising_edge(clk_61_44MHz)) then
--		dac_din_i_z <= dac_din_i;
--		dac_din_q_z <= dac_din_q;
--		
--		dac_din_i_z2 <= dac_din_i_z;
--		dac_din_q_z2 <= dac_din_q_z;
--	end if;
--end process;
	
----------------------------------------------------------------------------------------------------
-- Output serdes and LVDS buffer for DAC frame
----------------------------------------------------------------------------------------------------
oserdes_frame : oserdes
generic map (
  DATA_RATE_OQ => "DDR",
  DATA_RATE_TQ => "DDR",
  DATA_WIDTH => 4,
  INIT_OQ => '0',
  INIT_TQ => '0',
  SERDES_MODE => "MASTER",
  SRVAL_OQ => '0',
  SRVAL_TQ => '0',
  TRISTATE_WIDTH => 1
)
port map (
  oq        => dac_frame_prebuf,
  shiftout1 => open,
  shiftout2 => open,
  tq        => open,
  clk       => clk_122_88MHz,
  clkdiv    => clk_61_44MHz,
  d1        => frame,
  d2        => frame,
  d3        => frame,
  d4        => frame,
  d5        => '0',
  d6        => '0',
  oce       => '1',
  rev       => '0',
  shiftin1  => '0',
  shiftin2  => '0',
  sr        => io_rst,
  t1        => '0',
  t2        => '0',
  t3        => '0',
  t4        => '0',
  tce       => '0'
);

--output buffer
obufds_frame : obufds_lvdsext_25
port map (
  i  => dac_frame_prebuf,
  o  => dac_frame_p,
  ob => dac_frame_n
);


--process (clk_61_44MHz)
--begin 
--	if (rising_edge(clk_61_44MHz)) then
--		frame_z <= frame;
--		frame_z2 <= frame_z;
--	end if;
--end process;

----------------------------------------------------------------------------------------------------
-- Configuring the FMC150 card
----------------------------------------------------------------------------------------------------
-- the fmc150_spi_ctrl component configures the devices on the FMC150 card through the Serial
-- Peripheral Interfaces (SPI) and some additional direct control signals.
----------------------------------------------------------------------------------------------------
fmc150_spi_ctrl_inst : fmc150_spi_ctrl
port map (
  addr            => addr,
  idata           => idata,
  rd_n_wr         => rd_n_wr,
  cdce72010_valid => cdce72010_valid,
  ads62p49_valid  => ads62p49_valid,
  dac3283_valid   => dac3283_valid,
  amc7823_valid   => amc7823_valid,

  odata           => odata,
  busy            => busy,

  external_clock  => external_clock,

  rst             => arst,
  clk             => clk_100MHz,
  spi_sclk        => spi_sclk,
  spi_sdata       => spi_sdata,
  adc_n_en        => adc_n_en,
  adc_sdo         => adc_sdo,
  adc_reset       => adc_reset,
  cdce_n_en       => cdce_n_en,
  cdce_sdo        => cdce_sdo,
  cdce_n_reset    => cdce_n_reset,
  cdce_n_pd       => cdce_n_pd,
  ref_en          => ref_en,
  pll_status      => pll_status,
  dac_n_en        => dac_n_en,
  dac_sdo         => dac_sdo,
  mon_n_en        => mon_n_en,
  mon_sdo         => mon_sdo,
  mon_n_reset     => mon_n_reset,
  mon_n_int       => mon_n_int,
  prsnt_m2c_l     => prsnt_m2c_l
);

----------------------------------------------------------------------------------------------------
-- Connect entity
----------------------------------------------------------------------------------------------------
gpio_led(0) <= digital_mode;
gpio_led(1) <= '0';
gpio_led(2) <= external_clock;
gpio_led(3) <= ddc_duc_bypass;
gpio_led(4) <= pll_status;
gpio_led(5) <= mmcm_adac_locked;
gpio_led(6) <= mmcm_locked;
gpio_led(7) <= '0';

gpio_led_c <= gpio_sw_c;
gpio_led_e <= gpio_sw_e;
gpio_led_n <= gpio_sw_n;
gpio_led_s <= gpio_sw_s;
gpio_led_w <= gpio_sw_w;

digital_mode   <= gpio_dip_sw(5);
external_clock <= gpio_dip_sw(6);
ddc_duc_bypass <= gpio_dip_sw(7);

----------------------------------------------------------------------------------------------------
-- IDELAYCTRL
----------------------------------------------------------------------------------------------------
idelayctrl_inst : idelayctrl
port map (
  rst    => arst,
  refclk => clk_200Mhz,
  rdy    => open
);

----------------------------------------------------------------------------------------------------
-- ofdm Tx Data read from rom
----------------------------------------------------------------------------------------------------

process(clk_61_44MHz,signal_ce, sig_ofdmDataInReady)
begin
	if (rising_edge(clk_61_44MHz) and signal_ce = '1' and sig_ofdmDataInReady = '1') then
		sig_TxDataAvailable <= '1';
		if (unsigned(sig_TxDataAddr) >= 380) then
			sig_TxDataAddr <= (others=>'0');
		else
			sig_TxDataAddr <= std_logic_vector(sig_TxDataAddr + 1);
		end if;
	end if;
end process;
	
----------------------------------------------------------------------------------------------------
-- ofdm / dds mux switch
----------------------------------------------------------------------------------------------------

--process(gpio_dip_sw)
--begin
--	if (gpio_dip_sw(0) = '1') then
--		ofdm_dds_mux_to_duc_i <= dds_to_duc_i;
--		ofdm_dds_mux_to_duc_q <= dds_to_duc_q;
--	else
--		ofdm_dds_mux_to_duc_i <= ofdm_to_duc_i;
--		ofdm_dds_mux_to_duc_q <= ofdm_to_duc_q;
--	end if;
--end process;

--/////////////////////////////////////////////////////////////////////////////////

--process(clk_368_64MHz)
--begin
--	if (clk_368_64MHz'event and clk_368_64MHz = '1') then
--		if (gpio_dip_sw(0) = '1') then
--			ofdm_dds_mux_to_duc_i <= dds_to_duc_i;
--			ofdm_dds_mux_to_duc_q <= dds_to_duc_q;
--		else
--			ofdm_dds_mux_to_duc_i <= ofdm_to_duc_i;
--			ofdm_dds_mux_to_duc_q <= ofdm_to_duc_q;		
--		end if;
--	end if;
--end process;

--/////////////////////////////////////////////////////////////////////////////////

--process(clk_61_44MHz)
--begin
--	if (clk_61_44MHz'event and clk_61_44MHz = '1') then
--		if (gpio_dip_sw(0) = '1') then
--			ofdm_dds_mux_to_duc_i <= dds_to_duc_i;
--			ofdm_dds_mux_to_duc_q <= dds_to_duc_q;
--		else
--			ofdm_dds_mux_to_duc_i <= ofdm_to_duc_i;
--			ofdm_dds_mux_to_duc_q <= ofdm_to_duc_q;		
--		end if;
--	end if;
--end process;

--/////////////////////////////////////////////////////////////////////////////////

process(clk_61_44MHz)
begin
	if (clk_368_64MHz'event and clk_368_64MHz = '1') then
		sig_temp_debug_i <= ofdm_to_duc_i;
		sig_temp_debug_q <= ofdm_to_duc_q;		
	end if;
end process;

process(clk_368_64MHz)
begin
	if (clk_368_64MHz'event and clk_368_64MHz = '1') then
		if (gpio_dip_sw(0) = '1') then
			ofdm_dds_mux_to_duc_i <= dds_to_duc_i;
			ofdm_dds_mux_to_duc_q <= dds_to_duc_q;
		else
			ofdm_dds_mux_to_duc_i <= sig_temp_debug_i;
			ofdm_dds_mux_to_duc_q <= sig_temp_debug_q;		
		end if;
	end if;
end process;

----------------------------------------------------------------------------------------------------
-- End
----------------------------------------------------------------------------------------------------
end ml605_fmc150_syn;
